From f4881742088d99bfa0efd9b461308537a44196da Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Mon, 7 Jul 2014 14:46:03 -0700 Subject: [PATCH] fingerprint: Recover from fs::stat errors Fingerprinting will fail at an fs::stat() call if there is a broken symlink in a package's directory. This commit recovers from fs::stat() errors on broken symlinks by treating them as having mtime 0, which should not affect the overall fingerprint. Fix #135 --- src/cargo/sources/path.rs | 7 ++++++- tests/support/mod.rs | 41 +++++++++++++++++++++++++++++++++++-- tests/test_cargo_compile.rs | 14 +++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 26baccd57..e5a2a5757 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -106,7 +106,12 @@ impl Source for PathSource { fn walk(path: &Path, is_root: bool) -> CargoResult { if !path.is_dir() { - return Ok(try!(fs::stat(path)).modified) + // An fs::stat error here is either because path is a + // broken symlink, a permissions error, or a race + // condition where this path was rm'ed - either way, + // we can ignore the error and treat the path's mtime + // as 0. + return Ok(fs::stat(path).map(|s| s.modified).unwrap_or(0)) } // Don't recurse into any sub-packages that we have if !is_root && path.join("Cargo.toml").exists() { return Ok(0) } diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 7cd0faa4a..49ab97f93 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -51,11 +51,36 @@ impl FileBuilder { } } +#[deriving(PartialEq,Clone)] +struct SymlinkBuilder { + dst: Path, + src: Path +} + +impl SymlinkBuilder { + pub fn new(dst: Path, src: Path) -> SymlinkBuilder { + SymlinkBuilder { dst: dst, src: src } + } + + fn mk(&self) -> Result<(), String> { + try!(mkdir_recursive(&self.dirname())); + + fs::symlink(&self.dst, &self.src) + .with_err_msg(format!("Could not create symlink; dst={} src={}", + self.dst.display(), self.src.display())) + } + + fn dirname(&self) -> Path { + Path::new(self.src.dirname()) + } +} + #[deriving(PartialEq,Clone)] pub struct ProjectBuilder { name: String, root: Path, - files: Vec + files: Vec, + symlinks: Vec } impl ProjectBuilder { @@ -63,7 +88,8 @@ impl ProjectBuilder { ProjectBuilder { name: name.to_str(), root: root, - files: vec!() + files: vec!(), + symlinks: vec!() } } @@ -93,6 +119,13 @@ impl ProjectBuilder { self } + pub fn symlink(mut self, dst: T, + src: T) -> ProjectBuilder { + self.symlinks.push(SymlinkBuilder::new(self.root.join(dst), + self.root.join(src))); + self + } + // TODO: return something different than a ProjectBuilder pub fn build<'a>(&'a self) -> &'a ProjectBuilder { match self.build_with_result() { @@ -112,6 +145,10 @@ impl ProjectBuilder { try!(file.mk()); } + for symlink in self.symlinks.iter() { + try!(symlink.mk()); + } + Ok(()) } diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index 9fa6a8aa8..771988eb3 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -626,3 +626,17 @@ test!(self_dependency { assert_that(p.cargo_process("cargo-build"), execs().with_status(0)); }) + +test!(ignore_bogus_symlinks { + let p = project("foo") + .file("Cargo.toml", basic_bin_manifest("foo").as_slice()) + .file("src/foo.rs", main_file(r#""i am foo""#, []).as_slice()) + .symlink("Notafile", "bar"); + + assert_that(p.cargo_process("cargo-build"), execs()); + assert_that(&p.bin("foo"), existing_file()); + + assert_that( + process(p.bin("foo")), + execs().with_stdout("i am foo\n")); +}) -- 2.30.2